package mil.af.amc.adpetracker.dao.hibernate;

import mil.af.amc.adpetracker.dao.GenericDao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import java.sql.SQLException;
import java.util.List;

/**
 * Generic DAO extended by all other Hibernate DAOs
 *
 * @author TSgt Jason Ferguson
 */

public class HibernateGenericDao<T> extends HibernateDaoSupport implements GenericDao<T> {

    private static final Log log = LogFactory.getLog(HibernateGenericDao.class);

    private Class<T> type;

    public HibernateGenericDao(Class<T> type) {
        this.type = type;
    }

    @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
    public T getById(final int id) {

        T results = null;
        try {
            results = (T) getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException, SQLException {

                    Criteria crit = session.createCriteria(type);
                    crit.add(Restrictions.eq("id", id));
                    return crit.uniqueResult();

                }
            });
        } catch (DataAccessException e) {

            log.debug("getById() threw DataAccessException." , e);
            return null;
        }

        //getHibernateTemplate().initialize(results);

        return results;

    }

    public List<T> getAll() {

        List<T> results = null;
        try {
            results = (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException, SQLException {

                    Criteria crit = session.createCriteria(type);
                    return crit.list();
                }
            });
        } catch (DataAccessException e) {
            e.printStackTrace();
        }

        return results;
    }

    public int getCount() {

        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {

                Criteria crit = session.createCriteria(type);
                crit.setProjection(Projections.rowCount());
                return crit.uniqueResult();
            }
        });
    }

    public void delete(T persistentObject) {
        getHibernateTemplate().delete(persistentObject);
    }


    public void saveOrUpdate(T object) {

        try {
            getHibernateTemplate().saveOrUpdate(object);
        } catch (DataAccessException e) {
            e.printStackTrace();
        }
    }

    public void save(T object) {

        try {
            getHibernateTemplate().save(object);
        } catch (DataAccessException e) {
            e.printStackTrace();
            
        }
    }

    @SuppressWarnings("unchecked")
    public Integer add(T object) {

        try {
            return (Integer) getHibernateTemplate().save(object);
        } catch (DataAccessException e) {
            System.out.println("DATA ACCESS EXCEPTION!!!");
            e.printStackTrace();
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public T merge(T object) {
        return (T) getHibernateTemplate().merge(object);
    }

    @SuppressWarnings({"unchecked"})
    public List<T> getByQbe(T object) {

        DetachedCriteria crit = DetachedCriteria.forClass(type);
        Example e = Example.create(object);
        crit.add(e);

        return (List<T>) getHibernateTemplate().findByCriteria(crit);

//        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
//            public Object doInHibernate(Session session) throws HibernateException, SQLException {
//
//                Criteria crit = session.createCriteria(new Class<T>().getClass());
//                throw new UnsupportedOperationException();
//            }
//        });
        //return (List<T>) getHibernateTemplate().findByExample(object);
    }
}
